//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using OpenLS.Core;

namespace OpenLS.Spreadsheet
{
	class CompositeUndoUnit: ICompositeUndoUnit
	{
		public CompositeUndoUnit(string text)
		{
			this._text = text;
#if DEBUG
			StackTrace = new StackTrace().ToString();
#endif
		}
#if DEBUG
		private string StackTrace;
#endif
	   /* public CompositeUndoUnit(SRID id)
			: this(SR.Get(id))
		{
		}*/
		private readonly string _text;
		public string Text
		{
			get { return _text; }
		}

		public bool IsEmpty
		{
			get { return children == null || this.children.Count == 0; }
		}


		internal UndoManager UndoManager
		{
			get
			{
				object p = Parent;
				while (p is ICompositeUndoUnit)
					p = ((ICompositeUndoUnit)p).Parent;
				return (UndoManager)p ;
				
			}
		}
		#region ICompositeUndoUnit Members

		public void Add(IUndoUnit unit)
		{
			Children.Push(unit);
		}

		#endregion

		#region IUndoUnit Members

		public virtual void Do()
		{
			ICompositeUndoUnit u = GetEmptyClone();
			UndoManager m = UndoManager;
			if (m != null && m.IsEnabled)
				m.Open(u);
			if (Children.Count == 0)
				Debug.WriteLine("Warning empty children");
			DoSelf();
			if (m != null && m.IsEnabled)
				m.Close(u);
		}

		protected virtual void DoSelf()
		{
			while (children != null && Children.Count > 0)
			{
				IUndoUnit u = Children.Pop();
				u.Do();
			}
		}


		internal virtual  ICompositeUndoUnit GetEmptyClone()
		{
			return new CompositeUndoUnit(Text);
#if DEBUG
			isEmptyClone = true;
#endif
		}
#if DEBUG
		private bool isEmptyClone;
#endif

		#endregion
		private Stack<IUndoUnit> children ;

		public Stack<IUndoUnit> Children
		{
			get
			{
				if (children == null)
					children = new Stack<IUndoUnit>();
				return children; }
			set { children = value; }
		}

		#region ICompositeUndoUnit Members


		public void Close()
		{
			Close(OpenedUnit);
		}
		void Close(IUndoUnit unit)
		{
			Contract.Requires(unit == OpenedUnit);
			if (OpenedUnit.OpenedUnit != null)
			{
				OpenedUnit.OpenedUnit.Close();
			}
			ICompositeUndoUnit openUnit = OpenedUnit;
			OpenedUnit = null;
			Add(openUnit);
			LastUnit = openUnit;
		}

		ICompositeUndoUnit openedUnit;
		public ICompositeUndoUnit OpenedUnit
		{
			get { return openedUnit; }
			set { openedUnit = value; }
		}


		ICompositeUndoUnit lastUnit;
		public ICompositeUndoUnit LastUnit
		{
			get { return lastUnit; }
			set { lastUnit = value; }
		}
		#endregion


		#region ICompositeUndoUnit Members


		private object parent;

		public object Parent
		{
			get { return parent; }
			set { parent = value; }
		}
	
		#endregion

		#region ICompositeUndoUnit Members


		public virtual void Open(ICompositeUndoUnit newUnit)
		{
			if (newUnit == null)
				throw new ArgumentNullException("newUnit");
			ICompositeUndoUnit deepestOpenUnit = DeepestOpenUnit;
			if (deepestOpenUnit == null)
			{
				openedUnit = newUnit;
					newUnit.Parent = this;
			}
			else
			{
					newUnit.Parent = deepestOpenUnit;
				deepestOpenUnit.Open(newUnit);
			}
		}

 


		#endregion

		protected ICompositeUndoUnit DeepestOpenUnit
		{
			get
			{
				ICompositeUndoUnit result = OpenedUnit;
				if (result != null)
				{
					while (result.OpenedUnit != null)
					{
						result = result.OpenedUnit;
					}
				}
				return result;
			}
		}



		#region IUndoUnit Members


		public virtual bool Merge(IUndoUnit unit)
		{
			return false;
		}

		#endregion
	}
}
